﻿namespace StockSharp.Algo.Indicators.Oscillator
{
	using System.ComponentModel;

	using StockSharp.Algo.Indicators.Trend;

	/// <summary>
	/// Индекс относительной силы.
	/// </summary>
	[DisplayName("RSI")]
	[Description("Индекс относительной силы.")]
	public class RelativeStrengthIndex : LengthIndicator<decimal>
	{
		private readonly SmoothedMovingAverage _gain;
		private readonly SmoothedMovingAverage _loss;
		private bool _isInitialized;
		private decimal _last;

		/// <summary>
		/// Создать <see cref="RelativeStrengthIndex"/>.
		/// </summary>
		public RelativeStrengthIndex()
			: base(typeof(decimal))
		{
			_gain = new SmoothedMovingAverage();
			_loss = new SmoothedMovingAverage();
		}

		/// <summary>
		/// Сформирован ли индикатор.
		/// </summary>
		public override bool IsFormed { get { return _gain.IsFormed; } }

		/// <summary>
		/// Длина периода.
		/// </summary>
		public override int Length
		{
			get
			{
				return _gain.Length;
			}
			set
			{
				_loss.Length = _gain.Length = value;
				Reset();
			}
		}

		/// <summary>
		/// Обработать входное значение.
		/// </summary>
		/// <param name="input">Входное значение.</param>
		/// <returns>Результирующее значение.</returns>
		protected override decimal OnProcess(IIndicatorValue input)
		{
			var value = input.GetValue<decimal>();

			if (!_isInitialized)
			{
				_last = value;
				_isInitialized = true;
				return this.GetCurrentValue();
			}

			var delta = value - _last;

			var gainValue = _gain.Process(input.SetValue(delta > 0 ? delta : 0m)).GetValue<decimal>();
			var lossValue = _loss.Process(input.SetValue(delta > 0 ? 0m : -delta)).GetValue<decimal>();

			_last = value;

			if (lossValue == 0)
			{
				return 100m;
			}
			else if (gainValue / lossValue == 1)
			{
				return 0m;
			}
			else
			{
				return 100m - 100m / (1m + gainValue / lossValue);
			}
		}
	}
}